package cn.angis.flow.service;

import cn.angis.common.constant.DatePattern;
import cn.angis.common.util.DateU;
import cn.angis.db.model.DtoInput;
import cn.angis.flow.mapper.WarmFlowMapper;
import cn.angis.system.dto.input.DeptInput;
import cn.angis.system.dto.input.RoleInput;
import cn.angis.system.dto.input.UserInput;
import cn.angis.system.dto.output.DeptOutput;
import cn.angis.system.dto.output.RoleOutput;
import cn.angis.system.dto.output.UserOutput;
import cn.angis.system.service.AngisUserService;
import cn.angis.system.service.DeptService;
import cn.angis.system.service.RoleService;
import org.beetl.sql.solon.annotation.Db;
import org.dromara.warm.flow.core.utils.CollUtil;
import org.dromara.warm.flow.core.utils.MapUtil;
import org.dromara.warm.flow.core.utils.MathUtil;
import org.dromara.warm.flow.core.utils.StreamUtils;
import org.dromara.warm.flow.ui.dto.HandlerFunDto;
import org.dromara.warm.flow.ui.dto.HandlerQuery;
import org.dromara.warm.flow.ui.dto.TreeFunDto;
import org.dromara.warm.flow.ui.service.HandlerSelectService;
import org.dromara.warm.flow.ui.vo.HandlerFeedBackVo;
import org.dromara.warm.flow.ui.vo.HandlerSelectVo;
import org.noear.snack.core.utils.DateUtil;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;

import java.text.ParseException;
import java.util.*;


/**
 * 流程设计器-获取办理人权限设置列表接口实现类
 *
 * @author warm
 */
@Component
public class HandlerSelectServiceImpl implements HandlerSelectService {

    @Inject
    private AngisUserService angisUserService;

    @Inject
    private RoleService roleService;

    @Inject
    private DeptService deptService;

    @Db
    private WarmFlowMapper warmFlowMapper;

    /**
     * 获取办理人权限设置列表tabs页签，如：用户、角色和部门等，可以返回其中一种或者多种，按业务需求决定
     * @return tabs页签
     */
    @Override
    public List<String> getHandlerType() {
        return Arrays.asList("用户", "角色", "部门");
    }

    /**
     * 获取用户列表、角色列表、部门列表等，可以返回其中一种或者多种，按业务需求决定
     * @param query 查询参数
     * @return 结果
     */
    @Override
    public HandlerSelectVo getHandlerSelect(HandlerQuery query) {
        Date beginDate = null;
        Date endDate = null;
        try {
            beginDate = query.getBeginTime()!=null ? DateU.parseDate(query.getBeginTime(), DatePattern.NORM_DATE_PATTERN) : null;
            endDate = query.getEndTime()!=null ? DateU.parseDate(query.getEndTime(), DatePattern.NORM_DATE_PATTERN) : null;
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

        DtoInput input = new DtoInput();
        input.setBeginDate(beginDate);
        input.setEndDate(endDate);

        if ("角色".equals(query.getHandlerType())) {
            return getRole(query, input);
        }

        if ("部门".equals(query.getHandlerType())) {
            return getDept(query, input);
        }

        if ("用户".equals(query.getHandlerType())) {
            return getUser(query, input);
        }

        return new HandlerSelectVo();
    }

    @Override
    public List<HandlerFeedBackVo> handlerFeedback(List<String> storageIds) {
        List<HandlerFeedBackVo> handlerFeedBackVos = new ArrayList<>();
        if (CollUtil.isNotEmpty(storageIds)) {
            List<Long> roleIdList = new ArrayList<>();
            List<Long> deptIdList = new ArrayList<>();
            List<Long> userIdList = new ArrayList<>();

            // 分别过滤出用户、角色和部门的id，分别用集合存储
            for (String storageId : storageIds) {
                if (storageId.startsWith("role:")) {
                    roleIdList.add(Long.valueOf(storageId.replace("role:", "")));
                } else if (storageId.startsWith("dept:")) {
                    deptIdList.add(Long.valueOf(storageId.replace("dept:", "")));
                } else if (MathUtil.isNumeric(storageId)){
                    userIdList.add(Long.valueOf(storageId));
                }
            }

            Map<String, String> authMap = new HashMap<>();
            // 查询角色id对应的名称
            if (CollUtil.isNotEmpty(roleIdList)) {
                // 查询角色列表
                List<RoleOutput> roleList = warmFlowMapper.selectRoleByIds(roleIdList);
                authMap.putAll(StreamUtils.toMap(roleList, role -> "role:" + role.getId()
                        , RoleOutput::getName));
            }

            // 查询部门id对应的名称
            if (CollUtil.isNotEmpty(deptIdList)) {
                List<DeptOutput> deptList = warmFlowMapper.selectDeptByIds(deptIdList);
                authMap.putAll(StreamUtils.toMap(deptList, dept -> "dept:" + dept.getId()
                        , DeptOutput::getName));
            }

            // 查询用户id对应的名称
            if (CollUtil.isNotEmpty(userIdList)) {
                List<UserOutput> userList = warmFlowMapper.selectUserByIds(userIdList);
                authMap.putAll(StreamUtils.toMap(userList, user -> String.valueOf(user.getId())
                        , UserOutput::getNickName));
            }

            // 遍历storageIds，按照原本的顺序回显名称
            for (String storageId : storageIds) {
                handlerFeedBackVos.add(new HandlerFeedBackVo(storageId
                        , MapUtil.isEmpty(authMap) ? "": authMap.get(storageId)));
            }
        }

        return handlerFeedBackVos;
    }

    /**
     * 获取角色列表
     *
     * @param query 查询条件
     * @return HandlerSelectVo
     */
    private HandlerSelectVo getRole(HandlerQuery query, DtoInput input) {
        RoleInput roleInput = new RoleInput();
        roleInput.setCode(query.getHandlerCode());
        roleInput.setName(query.getHandlerName());
        roleInput.setBeginDate(input.getBeginDate());
        roleInput.setEndDate(input.getEndDate());
        // 查询角色列表
        List<RoleOutput> roleList = roleService.selectRoleList(roleInput);
        long total = roleList.size();

        // 业务系统数据，转成组件内部能够显示的数据, total是业务数据总数，用于分页显示
        HandlerFunDto<RoleOutput> handlerFunDto = new HandlerFunDto<>(roleList, total)
                // 以下设置获取内置变量的Function
                .setStorageId(role -> "role:" + role.getId()) // 前面拼接role:  是为了防止用户、角色的主键重复
                .setHandlerCode(RoleOutput::getCode) // 权限编码
                .setHandlerName(RoleOutput::getName) // 权限名称
                .setCreateTime(role -> DateUtil.format(role.getCreateDate(), DatePattern.NORM_DATETIME_PATTERN));

        return getHandlerSelectVo(handlerFunDto);
    }

    /**
     * 获取用户列表
     *
     * @param query 查询条件
     * @return HandlerSelectVo
     */
    private HandlerSelectVo getDept(HandlerQuery query, DtoInput input) {
        DeptInput deptInput = new DeptInput();
        deptInput.setName(query.getHandlerName());
        deptInput.setBeginDate(input.getBeginDate());
        deptInput.setEndDate(input.getEndDate());
        // 查询部门列表
        List<DeptOutput> deptList = deptService.selectDeptList(deptInput);
        long total = deptList.size();

        // 业务系统数据，转成组件内部能够显示的数据, total是业务数据总数，用于分页显示
        HandlerFunDto<DeptOutput> handlerFunDto = new HandlerFunDto<>(deptList, total)
                .setStorageId(dept -> "dept:" + dept.getId()) // 前面拼接dept:  是为了防止用户、部门的主键重复
                .setHandlerName(DeptOutput::getName) // 权限名称
                .setCreateTime(dept -> DateUtil.format(dept.getCreateDate(), DatePattern.NORM_DATETIME_PATTERN));

        return getHandlerSelectVo(handlerFunDto);

    }

    /**
     * 获取用户列表, 同时构建左侧部门树状结构
     *
     * @param query 查询条件
     * @return HandlerSelectVo
     */
    private HandlerSelectVo getUser(HandlerQuery query, DtoInput input) {
        UserInput userInput = new UserInput();
        userInput.setUsername(query.getHandlerCode());
        userInput.setNickName(query.getHandlerName());
        // 办理人用户选择列表，需要展示左侧树状部门，所以可能会通过部门id
        if (MathUtil.isNumeric(query.getGroupId())) {
            userInput.setDeptId(query.getGroupId());
        }
        userInput.setBeginDate(input.getBeginDate());
        userInput.setEndDate(input.getEndDate());
        // 查询用户列表
        List<UserOutput> userList = angisUserService.selectUserList(userInput);
        long total = userList.size();
        // 查询部门列表，构建树状结构
        List<DeptOutput> deptList = deptService.selectDeptList(new DeptInput());

        // 业务系统数据，转成组件内部能够显示的数据, total是业务数据总数，用于分页显示
        HandlerFunDto<UserOutput> handlerFunDto = new HandlerFunDto<>(userList, total)
                .setStorageId(UserOutput::getId)
                .setHandlerCode(UserOutput::getUsername) // 权限编码
                .setHandlerName(UserOutput::getNickName) // 权限名称
                .setCreateTime(user -> DateUtil.format(user.getCreateDate(), DatePattern.NORM_DATETIME_PATTERN))
                .setGroupName(UserOutput::getDeptName);

        // 业务系统机构，转成组件内部左侧树列表能够显示的数据
        TreeFunDto<DeptOutput> treeFunDto = new TreeFunDto<>(deptList)
                .setId(DeptOutput::getId) // 左侧树ID
                .setName(DeptOutput::getName) // 左侧树名称
                .setParentId(DeptOutput::getParentId); // 左侧树父级ID

        return getHandlerSelectVo(handlerFunDto, treeFunDto);
    }
}
